﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using Celeriq.Common;
using Celeriq.Server.Interfaces;
using Celeriq.Utilities;

namespace Celeriq.RepositoryAPI
{
    [Serializable]
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
    public class RepositoryService : Celeriq.Common.IDataModel, Celeriq.Server.Interfaces.IRepositoryService
    {
        private Celeriq.RepositoryAPI.Repository _repository = null;
        private Guid _repositoryId = Guid.Empty;
        private long _minMemory = 0;
        private Celeriq.Client.Interfaces.ISystemCore _system = null;

        public RepositoryService(Celeriq.Client.Interfaces.ISystemCore system)
        {
            _system = system;
            try
            {
                _minMemory = System.Diagnostics.Process.GetCurrentProcess().WorkingSet64;
            }
            catch (Exception ex)
            {
                Logger.LogError(ex);
                throw;
            }
        }

        public DateTime LastAccess
        {
            get { return _repository.LastAccess; }
        }

        public void UnloadData()
        {
            try
            {
                if (_repository != null)
                    _repository.UnloadData();
            }
            catch (Exception ex)
            {
                Logger.LogError(ex);
            }
        }

        public void LoadData(UserCredentials credentials)
        {
            try
            {
                if (_repository != null)
                    _repository.Query(new DataQuery() {Credentials = credentials});
            }
            catch (Exception ex)
            {
                Logger.LogError(ex);
            }
        }

        public string[] UpdateData(IEnumerable<DataItem> list, UserCredentials credentials)
        {
            var errorList = new List<string>();
            try
            {
                if (_repository == null)
                    errorList.Add("The repository has not been initialized!");
                else
                    _repository.UpdateIndexList(list, credentials);
            }
            catch (Exception ex)
            {
                Logger.LogError(ex);
                errorList.Add(ex.ToString());
            }
            return errorList.ToArray();
        }

        public string[] DeleteData(IEnumerable<DataItem> item, UserCredentials credentials)
        {
            var errorList = new List<string>();
            try
            {
                if (_repository == null)
                    errorList.Add("The repository has not been initialized!");
                else
                    _repository.DeleteData(item, credentials);
            }
            catch (Exception ex)
            {
                Logger.LogError(ex);
                errorList.Add(ex.ToString());
            }
            return errorList.ToArray();
        }

        public string[] Clear(UserCredentials credentials)
        {
            var errorList = new List<string>();
            try
            {
                if (_repository == null)
                {
                    errorList.Add("The repository has not been initialized!");
                }
                else
                {
                    _repository.Clear(credentials);
                }
            }
            catch (Exception ex)
            {
                Logger.LogError(ex);
                errorList.Add(ex.ToString());
            }
            return errorList.ToArray();
        }

        public DataQueryResults Query(DataQuery query)
        {
            var retval = new DataQueryResults();
            try
            {
                if (_repository == null)
                {
                    retval.ErrorList = new string[] {"The repository has not been initialized!"};
                }
                else
                {
                    retval = _repository.Query(query);
                }
            }
            catch (Exception ex)
            {
                Logger.LogError(ex);
                retval.ErrorList = new string[] {ex.ToString()};
            }
            return retval;
        }

        public int StartUp(Celeriq.Server.Interfaces.ServiceStartup startup)
        {
            if (_repository != null)
                throw new Exception("The repository has already been initialized!");

            if (startup == null)
                throw new Exception("The startup object must be specified!");

            if (startup.RepositoryDefinition == null)
                throw new Exception("The repository definition must be specified!");

            if (string.IsNullOrEmpty(startup.RepositoryFolder))
                throw new Exception("The repository folder must be specified!");

            try
            {
                _repositoryId = startup.RepositoryDefinition.ID;
                var masterKeys = ConfigurationSettings.MasterKeys;
                _repository = new Celeriq.RepositoryAPI.Repository(startup, masterKeys, _system);
                //var results = _repository.Query(new DataQuery());
                //return results.TotalRecordCount;
                return (int) _repository.GetItemCount();
            }
            catch (Exception ex)
            {
                Logger.LogError(ex);
                return 0;
            }
        }

        public void ShutDown()
        {
            if (_repository == null)
                throw new Exception("The repository has not been initialized!");

            _repository.ShutDown();
            _repository = null;
        }

        /// <summary>
        /// Clears all data from the repository
        /// </summary>
        /// <param name="startup"></param>
        public void Reset(Celeriq.Server.Interfaces.ServiceStartup startup)
        {
            try
            {
                if (_repository == null) StartUp(startup);
                _repository.Reset(startup);
            }
            catch (Exception ex)
            {
                Logger.LogError(ex);
                throw;
            }
        }

        public Guid GetID()
        {
            return _repositoryId;
        }

        /// <summary>
        /// Copies the entire repository to an archive file
        /// </summary>
        public bool ExportSchema(Celeriq.Server.Interfaces.ServiceStartup startup, UserCredentials credentials, string backupFile)
        {
            try
            {
                if (_repository == null) StartUp(startup);
                return _repository.ExportSchema(startup, credentials, backupFile);
            }
            catch (Exception ex)
            {
                Logger.LogError(ex);
                throw;
            }
        }

        /// <summary>
        /// Copies the entire repository to an archive file
        /// </summary>
        public bool Backup(Celeriq.Server.Interfaces.ServiceStartup startup, UserCredentials credentials, string backupFile)
        {
            try
            {
                if (_repository == null) StartUp(startup);
                return _repository.Backup(startup, credentials, backupFile);
            }
            catch (Exception ex)
            {
                Logger.LogError(ex);
                throw;
            }
        }

        public bool Restore(Celeriq.Server.Interfaces.ServiceStartup startup, UserCredentials credentials, string backupFile)
        {
            try
            {
                if (_repository == null) StartUp(startup);
                return _repository.Restore(startup, credentials, backupFile);
            }
            catch (Exception ex)
            {
                Logger.LogError(ex);
                throw;
            }
        }

        /// <summary>
        /// Returns the size on disk of the repository data
        /// </summary>
        /// <returns></returns>
        public long GetDataDiskSize(UserCredentials credentials)
        {
            try
            {
                if (_repository == null) return 0;
                return _repository.GetDataDiskSize(credentials);
            }
            catch (Exception ex)
            {
                Logger.LogError(ex);
                throw;
            }
        }

        /// <summary>
        /// Returns the size of memory of the repository data
        /// </summary>
        /// <returns></returns>
        public long GetDataMemorySize(UserCredentials credentials)
        {
            try
            {
                if (_repository == null) return 0;
                return _repository.GetDataMemorySize(credentials);
            }
            catch (Exception ex)
            {
                Logger.LogError(ex);
                throw;
            }
        }

        /// <summary>
        /// Returns the number of items in the repository
        /// </summary>
        /// <returns></returns>
        public long GetItemCount(UserCredentials credentials)
        {
            try
            {
                if (_repository == null) return 0;
                return _repository.GetItemCount(credentials);
            }
            catch (Exception ex)
            {
                Logger.LogError(ex);
                throw;
            }
        }

        public void Compress(UserCredentials credentials)
        {
            try
            {
                if (_repository == null)
                    throw new Exception("The repository has not been initialized!");

                _repository.Compress(credentials);
            }
            catch (Exception ex)
            {
                Logger.LogError(ex);
                throw;
            }
        }

        public bool IsLoaded
        {
            get
            {
                try
                {
                    if (_repository == null)
                        return false;
                    else
                        return _repository.IsLoaded;
                }
                catch (Exception ex)
                {
                    Logger.LogError(ex);
                    throw;
                }
            }
        }

        public ProfileItem[] GetProfile(UserCredentials credentials, long lastProfileId)
        {
            return _repository.GetProfile(credentials, lastProfileId);
        }

    }
}